package net.wendal.luat.air720;

import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import org.nutz.http.Http;
import org.nutz.http.Request;
import org.nutz.http.Response;
import org.nutz.http.Sender;
import org.nutz.http.Request.METHOD;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.Xmls;
import org.nutz.lang.random.R;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;

// https://zh.wikipedia.org/wiki/HTTP%E6%91%98%E8%A6%81%E8%AE%A4%E8%AF%81
public class Air720Master {
    
    private static final Log log = Logs.get();

    // 网卡地址,通常就是192.168.0.1
    public String HOST = "http://192.168.0.1";
    // 根据观察, realm总是Highwmg
    public String realm = "Highwmg";
    // 通过直接访问login.cgi获取的nonce
    public String nonce;
    // qop总是auth
    public String qop = "auth";
    // 默认账号admin
    public String username = "admin";
    // 默认密码admin
    public String password = "admin";
    // 请求计数器
    public AtomicInteger reqId = new AtomicInteger(2);
    

    public static void main(String[] args) {
        // 初始化
        Air720Master master = new Air720Master();
        master.init();
        // 获取首页的状态,非常详细, 含iccid/imsi/imei/信号强度等等
        NutMap re = master.xml_action_get("duster", "status1");
        log.debug(Json.toJson(re));
        // 获取4G配置
        re = master.xml_action_get("duster", "wan");
        log.debug(Json.toJson(re));
        // 获取固件版本
        re = master.xml_action_get("duster", "firmware");
        log.debug(Json.toJson(re));
    }
    
    public void init() {
        // 单纯访问login.cgi,会返回WWW-Authenticate
        Response resp = Http.get(HOST + "/login.cgi");
        if (!resp.isOK())
            return;
        String WWW_Authenticate = resp.getHeader().get("WWW-Authenticate");
        log.debugf("WWW-Authenticate: %s", WWW_Authenticate);
        // 稍微转一下,变成json格式,方便解析
        WWW_Authenticate = WWW_Authenticate.replaceAll(" ", "");
        WWW_Authenticate = WWW_Authenticate.replaceAll("=", ":");
        NutMap auth = Json.fromJson(NutMap.class, "{" + WWW_Authenticate + "}");
        // 可以获取realm/nonce/qop,但只有nonce会变
        //realm = auth.getString("Digestrealm");
        nonce = auth.getString("nonce");
        //qop = auth.getString("qop");
        log.debugf("realm=%s,nonce=%s,qop=%s", realm, nonce, qop);
        // 执行登录操作
        // window.location.protocol + "//" + window.location.host + "/login.cgi?Action=Digest&username="+username+"&realm="+Authrealm+"&nonce="+nonce+"&response="+DigestRes+"&qop="+AuthQop+"&cnonce="+AuthCnonce + "&temp=asr";
        doLogin();
    }
    
    // http://192.168.0.1/xml_action.cgi?method=get&module=duster&file=status1
    // 全部状态? status1
    // 流量信息 statistics
    // 上网配置 wan
    // 局域网配置 lan
    // PIN/PUK设置 pin_puk
    // USSD设置 ussd
    // 联网设备 device_management_all
    // 设备统计 device_management
    // 日志 detailed_log
    // 自定义防火墙 custom_fw
    // 端口过滤 port_filter
    // 端口转发 port_forwarding
    // 电话本 phonebook
    // 短信 message
    // 管理员配置 admin
    // 固件版本 firmware
    // 重启 reset
    public NutMap xml_action_get(String module, String file) {
        Request req = Request.create(HOST + "/xml_action.cgi", METHOD.GET);
        req.getParams().put("method", "get");
        req.getParams().put("module", module);
        req.getParams().put("file", file);
        fixAuth("/cgi/xml_action.cgi", req);
        Response resp = Sender.create(req).send();
        String cnt = resp.getContent();
        if (resp.isOK() && !Strings.isBlank(cnt)) {
            NutMap re = Xmls.xmlToMap(cnt);
            return re;
        }
        else {
            log.debug(resp.getStatus());
            log.debug(cnt);
        }
        return null;
    }
    
    public void fixAuth(String uri, Request req) {
        // Authorization: Digest username="admin", realm="Highwmg", nonce="182655", 
        // uri="/cgi/xml_action.cgi", response="2d09e0dca7939cdae09db4bcc557aa01", 
        // qop=auth, nc=00000003, cnonce="6aef0fa0bba19d8d"
        NutMap re = fixAuthMap(uri, req.getMethod().name().toUpperCase(), null);
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, Object> en : re.entrySet()) {
            switch (en.getKey()) {
            case "qop":
            case "nc":
                sb.append(en.getKey()).append("=").append(en.getValue()).append(", ");
                break;
            default:
                sb.append(en.getKey()).append("=\"").append(en.getValue()).append("\", ");
                break;
            }
        }
        sb.setLength(sb.length() - 2);
        log.debug(sb);
        req.getHeader().set("Authorization", sb.toString());
    }
/**
function getAuthHeader(requestType,file) {
    // return getCookie("Authheader");
    var rand, date, salt, strAuthHeader;
    var  tmp, DigestRes,AuthCnonce_f;
    var HA1, HA2;



    HA1 = hex_md5(username+ ":" + Authrealm + ":" + passwd);
    HA2 = hex_md5( requestType + ":" + "/cgi/xml_action.cgi");

    rand = Math.floor(Math.random()*100001)
           date = new Date().getTime();

    salt = rand+""+date;
    tmp = hex_md5(salt);
    AuthCnonce_f = tmp.substring(0,16);
    //AuthCnonce_f = tmp;

    var strhex = hex(GnCount);
    var temp = "0000000000" + strhex;
    var  Authcount = temp.substring(temp.length-8);
    DigestRes =hex_md5(HA1 + ":" + nonce + ":" + Authcount + ":" + AuthCnonce_f  + ":" + AuthQop + ":"+ HA2);


    GnCount++;
    strAuthHeader = "Digest " + "username=\"" + username + "\", realm=\"" + Authrealm + "\", nonce=\"" + nonce + "\", uri=\"" + "/cgi/xml_action.cgi" + "\", response=\"" + DigestRes + "\", qop=" + AuthQop + ", nc=" + Authcount + ", cnonce=\"" + AuthCnonce_f  + "\"" ;
    DigestHeader = strAuthHeader ;
    return strAuthHeader;
}
 */
    public NutMap fixAuthMap(String uri, String method, String cnonce) {
        NutMap re = new NutMap();
        re.put("Digest username", username);
        re.put("realm", realm);
        re.put("nonce", nonce);
        re.put("uri", uri);
        // 
        String HA1 = Lang.md5(String.format("%s:%s:%s", username, realm, password));
        String HA2 = Lang.md5(String.format("%s:%s", method, uri));
        String nc = String.format("%08X", reqId.getAndIncrement());
        if (cnonce == null)
            cnonce = R.UU32().substring(0, "6aef0fa0bba19d8d".length());
        String response = Lang.md5(String.format("%s:%s:%s:%s:%s:%s", HA1, nonce, nc, cnonce, qop, HA2));
        re.put("response", response);
        re.put("qop", qop);
        re.put("nc", nc);
        re.put("cnonce", cnonce);
        return re;
    }
/**
function doLogin(username1,passwd1) {
    var url = window.location.protocol + "//" + window.location.host + "/login.cgi";
    var loginParam =  getAuthType(url);
    //alert(loginParam);
    if(loginParam!=null) {
        var loginParamArray = loginParam.split(" ");
        if(loginParamArray[0] =="Digest") {
            Authrealm   = getValue(loginParamArray[1]);
            nonce = getValue(loginParamArray[2]);
            AuthQop = getValue(loginParamArray[3]);

            username = username1;
            passwd = passwd1;
            var rand, date, salt, strResponse;

            Gnonce = nonce;
            var tmp, DigestRes;
            var HA1, HA2;
            HA1 = hex_md5(username+ ":" + Authrealm + ":" + passwd);
            HA2 = hex_md5("GET" + ":" + "/cgi/protected.cgi");

            rand = Math.floor(Math.random()*100001)
                   date = new Date().getTime();

            salt = rand+""+date;
            tmp = hex_md5(salt);
            AuthCnonce = tmp.substring(0,16);


            DigestRes = hex_md5(HA1 + ":" + nonce + ":" + "00000001" + ":" + AuthCnonce + ":" + AuthQop + ":" + HA2);

            url = window.location.protocol + "//" + window.location.host + "/login.cgi?Action=Digest&username="+username+"&realm="+Authrealm+"&nonce="+nonce+"&response="+DigestRes+"&qop="+AuthQop+"&cnonce="+AuthCnonce + "&temp=asr";
            if(login_done(authentication(url))) {
                strResponse = "Digest username=\"" + username + "\", realm=\"" + Authrealm + "\", nonce=\"" + nonce + "\", uri=\"" + "/cgi/protected.cgi" + "\", response=\"" + DigestRes + "\", qop=" + AuthQop + ", nc=00000001" + ", cnonce=\"" + AuthCnonce + "\"" ;

                return 1;
            } else {
                // show error message...
                return 0;
            }

            return strResponse;
        }
    }
    return -1;
}
 */
    public boolean doLogin() {
        String HA1 = Lang.md5(username + ":" + realm + ":" + password);
        String HA2 = Lang.md5("GET" + ":" + "/cgi/protected.cgi");
        String cnonce = R.UU32().substring(0, "6aef0fa0bba19d8d".length());
        String DigestRes = Lang.md5(HA1 + ":" + nonce + ":" + "00000001" + ":" + cnonce + ":" + qop + ":" + HA2);
        String url = HOST + "/login.cgi?Action=Digest&username="+username+"&realm="+realm+"&nonce="+nonce+"&response="+DigestRes+"&qop="+qop+"&cnonce="+cnonce + "&temp=asr";
        Request req = Request.create(url, METHOD.GET);
        fixAuth("/cgi/xml_action.cgi", req);
        Response resp = Sender.create(req).send();
        if (resp.isOK()) {
            log.debug("登录成功: " + resp.getStatus());
            return true;
        }
        else {
            log.debug("登录失败: " + resp.getStatus());
            return false;
        }
    }
}
